package teaching.io.exer;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import teaching.io.entity.Employee;

/**
 * 数据文件存取对象信息示例。
 *
 * @author deng.zhao
 *
 */
public class RamdomAccessFileExample {
	/**
	 * 记录数量。
	 */
	public static final int RECORD_NUMBER = 100;
	/**
	 * 记录大小。
	 */
	public static final int RECORD_SIZE = 48;
	/**
	 * 姓名大小。
	 */
	public static final int NAME_SIZE = 15;

	/**
	 * 创建文件。
	 */
	public static void createFile() {
		final Employee employee = new Employee();
		try (final RandomAccessFile out = new RandomAccessFile("d:/stu.dat", "rw");) {
			for (int i = 0; i < RECORD_NUMBER; i++) {
				for (int j = 0; j < RECORD_SIZE; j++) {
					out.write(0);
				}
			}
		} catch (final FileNotFoundException e) {
			e.printStackTrace();
		} catch (final IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 向给定的数据输出，写出给定大小的字符串。
	 *
	 * @param str
	 *            字符串；
	 * @param size
	 *            大小；
	 * @param out
	 *            数据输出；
	 * @throws IOException
	 *             IO异常；
	 */
	public static void writeFixedString(String str, int size, DataOutput out) throws IOException {
		for (int i = 0; i < size; i++) {
			char ch = 0;
			if (i < str.length()) {
				ch = str.charAt(i);
			}
			out.writeChar(ch);
		}
	}

	/**
	 * 向给定的数据输出，写出员工信息。
	 *
	 * @param employee
	 *            员工信息；
	 * @param out
	 *            数据输出；
	 * @throws IOException
	 *             IO异常；
	 */
	public static void writeEmployee(Employee employee, DataOutput out) throws IOException {
		final GregorianCalendar calender = new GregorianCalendar();
		calender.setTime(employee.getHireDate());
		out.writeInt(employee.getId());
		writeFixedString(employee.getName(), NAME_SIZE, out);
		out.writeDouble(employee.getSalary());
		out.writeInt(calender.get(Calendar.YEAR));
		out.writeByte(calender.get(Calendar.MONTH));
		out.writeByte(calender.get(Calendar.DATE));
	}

	/**
	 * 将员工信息写出至文件。
	 *
	 * @param employee
	 *            员工信息；
	 */
	public static void writeRecord(Employee employee) {
		final int employeeId = employee.getId();
		try (final RandomAccessFile out = new RandomAccessFile("d:/stu.dat", "rw");) {
			if (employeeId >= 1 && employeeId <= RECORD_NUMBER) {
				out.seek((employeeId - 1) * RECORD_SIZE);
				writeEmployee(employee, out);
			}
		} catch (final FileNotFoundException e) {
			e.printStackTrace();
		} catch (final IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 从给定的数据输入，读入给定大小的字符串。
	 *
	 * @param size
	 *            大小
	 * @param in
	 *            数据输入；
	 * @return 字符串；
	 * @throws IOException
	 *             IO异常；
	 */
	public static String readFixedString(int size, DataInput in) throws IOException {
		final StringBuffer stringBuffer = new StringBuffer();
		for (int i = 0; i < size; i++) {
			stringBuffer.append(in.readChar());
		}
		return stringBuffer.toString().replace('\0', ' ').trim();
	}

	/**
	 * 从给定的数据输入，读入员工信息。
	 *
	 * @param in
	 *            数据输入；
	 * @return 字符串；
	 * @throws IOException
	 *             IO异常；
	 */
	public static Employee readEmployee(DataInput in) throws IOException {
		final Employee employee = new Employee();
		employee.setId(in.readInt());
		employee.setName(readFixedString(NAME_SIZE, in));
		employee.setSalary(in.readDouble());
		final GregorianCalendar calender = new GregorianCalendar(in.readInt(), in.readByte(), in.readByte());
		employee.setHireDate(calender.getTime());
		return employee;
	}

	/**
	 * 根据员工编号，读入员工信息。
	 *
	 * @param employeeId
	 *            员工编号；
	 * @return 员工信息；
	 */
	public static Employee readRecord(int employeeId) {
		Employee employee = null;
		try (final RandomAccessFile in = new RandomAccessFile("d:/stu.dat", "r");) {
			if (employeeId >= 1 && employeeId <= RECORD_NUMBER) {
				in.seek((employeeId - 1) * RECORD_SIZE);
				employee = readEmployee(in);
			}
		} catch (final FileNotFoundException e) {
			e.printStackTrace();
		} catch (final IOException e) {
			e.printStackTrace();
		}
		return employee;
	}

	/**
	 * 测试用主函数。
	 *
	 * @param args
	 *            参数列表；
	 */
	public static void main(String[] args) {
		final List<Employee> employees = new ArrayList<Employee>();
		employees.add(new Employee(6, "张无忌", 5150d, new GregorianCalendar(1997, Calendar.JANUARY, 28).getTime()));
		employees.add(new Employee(1, "郭靖", 4500d, new GregorianCalendar(1996, Calendar.DECEMBER, 7).getTime()));
		employees.add(new Employee(2, "黄蓉", 5545.5d, new GregorianCalendar(1997, Calendar.DECEMBER, 20).getTime()));

		createFile();
		for (final Employee employee : employees) {
			writeRecord(employee);
		}

		System.out.println(readRecord(2));
		System.out.println(readRecord(6));
	}
}
